package belf.migrate.engine.ddl.helper.sqlserver;

import belf.migrate.api.exception.APIErrorCode;
import belf.migrate.api.model.QualifiersModel;
import belf.migrate.core.exception.BelfRuntimeException;
import belf.migrate.core.jdbc.FunctionModel;
import belf.migrate.core.jdbc.TypeModel;
import belf.migrate.core.util.StringTool;
import belf.migrate.engine.ddl.BaseDDLConvert;
import belf.migrate.engine.job.exception.ConvertViewException;
import belf.migrate.plugin.mysql.antlr.MySqlParser;
import belf.migrate.plugin.sqlserver.antlr.TSqlParser;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class SqlServerAntlrBuilder {
    /** sb.append()时，这些符号前不加空格 */
    public static List<String> TRIMLEFT_SYMBOLS = Arrays.asList("'", "(", ")", "\"", ".", ",", ";");

    /** 右侧要加空格的符号 */
    private static List<String> RIGHT_BLAND_SYMBOLS = Arrays.asList(")", ",", "\"");

    /** 组合数学符号的前缀 */
    public static List<String> PREFIX_SYMBOLS = Arrays.asList("!", "&", "<", ">", "=");

    /** 组合数学符号的后缀 */
    public static List<String> SUFFIX_SYMBOLS = Arrays.asList("=",">", "<");

    /** 前后需要换行的关键词 */
    public static List<String> LINEBREAK_KEYWORDS = Arrays.asList(
            "FROM",
            "WHERE",
            "ORDER BY",
            "GROUP BY",
            "THEN",
            "BEGIN");

    private BaseDDLConvert ddlConvert;
    private QualifiersModel qualifiersModel;
    protected Map<String, FunctionModel> funcMapping;
    protected Map<String, TypeModel> typeMapping;

    private StringBuilder sb;

    private String schema;

    public SqlServerAntlrBuilder(BaseDDLConvert ddlConvert,
                                 StringBuilder sb,
                                 QualifiersModel qualifiersModel,
                                 String schema) {
        this.ddlConvert = ddlConvert;
        this.funcMapping = ddlConvert.getFuncMapping();
        this.typeMapping = ddlConvert.getTypeMapping();
        this.sb = sb;
        this.qualifiersModel = qualifiersModel;

        this.schema = schema;
    }

    public void output(TerminalNode node) {
        String text = node.getText().trim();

        if (text.equals(";")) {
            appendTrimLeft(text);
            sb.append('\n');
        } else if(text.equals(".") && node.getParent() instanceof TSqlParser.Full_table_nameContext) {
            // 形如id_.id_，只处理最后的id_，中间的点忽略
        } else if (TRIMLEFT_SYMBOLS.contains(text)) {
            appendTrimLeft(text);
        } else if (PREFIX_SYMBOLS.contains(text)) {
            sb.append(text);
        } else if (SUFFIX_SYMBOLS.contains(text)) {
            appendTrimLeft(text);
        } else if (LINEBREAK_KEYWORDS.contains(text)) {
            sb.append('\n');
            sb.append(text);
            sb.append('\n');
        } else if (node.getParent() instanceof TSqlParser.Id_Context) { // 是id_标识

            if (ddlConvert.hasAncestor("Full_table_nameContext", node)) { // 是表名称
                TSqlParser.Full_table_nameContext fullTableNameContext =
                        (TSqlParser.Full_table_nameContext)ddlConvert.getParent("Full_table_nameContext", node);
                if (fullTableNameContext.getParent() instanceof TSqlParser.Full_column_nameContext) {
                    StringBuilder buff = new StringBuilder();
                    buff.append(qualifiersModel.getLeftQuote());
                    buff.append(StringTool.removeChars(text, "[]"));
                    buff.append(qualifiersModel.getRightQuote());
                    sb.append(buff);
                    return;
                }
                if (fullTableNameContext.id_().size() > 1 &&
                        fullTableNameContext.id_(0).equals(node.getParent())) { //第一个节点是表名的前缀就忽略了
                    return;
                }

                String tableName = text; //给表名加上schema
                StringBuilder buff = new StringBuilder();
                buff.append(qualifiersModel.getLeftQuote());
                buff.append(schema);
                buff.append(qualifiersModel.getRightQuote());
                buff.append(".");
                buff.append(qualifiersModel.getLeftQuote());
                buff.append(StringTool.removeChars(tableName, "[]"));
                buff.append(qualifiersModel.getRightQuote());
                sb.append(buff.append(" "));
            }  else { //是字段名称
                StringBuilder buff = new StringBuilder();
                buff.append(qualifiersModel.getLeftQuote());
                buff.append(StringTool.removeChars(text, "[]"));
                buff.append(qualifiersModel.getRightQuote());
                sb.append(buff.append(" "));
            }
        } else if (node.getParent() instanceof TSqlParser.Built_in_functionsContext) {
            // 对于函数，简单地替换为达梦支持的函数名。函数参数及顺序不在这里处理，无法穷尽
            String functionName = text.toUpperCase();

            if (null != funcMapping && funcMapping.containsKey(functionName)) { //函数必须在“db-function-mapping”下的xml文件中定义，否则会出错
                if (funcMapping.get(functionName) != null && StringUtils.isNotEmpty(funcMapping.get(functionName).getTo())) { //有可替换的函数，直接替换
                    text = funcMapping.get(functionName).getTo();
                } else { //无可替换函数，需要报错
                    ddlConvert.addWarning(new ConvertViewException(APIErrorCode.CONVERT_SQLSERVER_DDL_ERROR,
                            ddlConvert.getTaskType() + "的DDL转化遇到无法自动转化的函数:" + text,
                            ddlConvert.getSql(),
                            text));
                }
            }
            sb.append(' ');
            sb.append(text);
        } else {
            sb.append(text);
            sb.append(' ');
        }
    }

    public void append(String text) {
        sb.append(text);
    }

    /**
     * 将文本append到sb前，去除sb后面的空格
     * @param text 要append的文本
     */
    public void appendTrimLeft(String text) {
        appendTrimLeft(sb, text);
    }

    /**
     * 将文本append到sb前，去除sb后面的空格
     * @param sb 文本缓冲区
     * @param text 要append的文本
     */
    public static void appendTrimLeft(StringBuilder sb, String text) {
        while (!(sb.isEmpty()) && sb.charAt(sb.length() - 1) == ' ') {
            sb.deleteCharAt(sb.length() - 1);
        }
        sb.append(text);
        if (RIGHT_BLAND_SYMBOLS.contains(text)) {
            sb.append(" ");
        }
    }

    public char charAt(int i) {
        return sb.charAt(i);
    }

    public int length() {
        return sb.length();
    }

    public void deleteCharAt(int i) {
        sb.deleteCharAt(i);
    }

    public String toSql() {
        return sb.toString();
    }

    public void addError(BelfRuntimeException exception) {
        ddlConvert.addWarning(exception);
    }

}
